import {BaseCodeGenerator} from "./code_generater/BaseCodeGenerater";
import {Workbook, Worksheet} from "exceljs";
import {Utils} from "../Utils";
import {ConfigDataEntity} from "../generate/entitas";
import {PlatForm} from "./PlatForm";
import {EntityService} from "./service/EntityService";
import path = require("path");
import {ExcelService} from "./service/ExcelService";
import MethodInfo from "./MethodInfo";

export class ExcelParser
{
	excelDataList : Array<ConfigDataEntity> = new Array<ConfigDataEntity>()
	codeGenerators : Array<BaseCodeGenerator> = new Array<BaseCodeGenerator>()

	parsePathList : Array<string> = new Array<string>()

	constructor()
	{

	}

	addParsePath(path : string){
		this.parsePathList.push(path)
	}

	addCodeGenerator(generator : BaseCodeGenerator){
		this.codeGenerators.push(generator)
	}

	parseData(callback){
		this.prepareDataList().then(()=>{
			try {
				this.mergeExportEntity()
				if (callback != null){
					callback()
				}
			}
			catch (e) {
				console.error(`[导出错误] 导出遇到错误, ${e}, ${e.stack}`)
			}
		})
	}

	async prepareDataList(){
		for (let i = 0; i < this.parsePathList.length; i++) {
			let v = this.parsePathList[i]
			var fileNameList = Utils.getFileListWithSuffix(v, ".xlsx")
			for (let i = 0; i < fileNameList.length; i++) {
				if (fileNameList[i].fullName.indexOf("~$") != -1){
					continue
				}
				console.log(`readFile ${fileNameList[i].fullName}`)
				await this.readFile(fileNameList[i].fullName)
			}
		}
	}

	exportData(){
		let allEntity = context.GetEntitiesByExportPlatformIndex(true, PlatForm.All)
		// for (let platFormKey in PlatForm) {
		// 	if (platFormKey == PlatForm.All){
		// 		continue
		// 	}
			let list = new Array<ConfigDataEntity>()
			let platEntity = context.GetEntitiesByExportPlatformIndex(true,  PlatForm.All)
			let entityList = list.concat(allEntity, platEntity)
			this.generateData(entityList,  PlatForm.All as PlatForm)
		// }
	}

	generateCode(){
		let allEntity = context.GetEntitiesByExportPlatformIndex(true, PlatForm.All)
		// for (let platFormKey in PlatForm) {
		// 	if (platFormKey == PlatForm.All){
		// 		continue
		// 	}
			let list = new Array<ConfigDataEntity>()
			let platEntity = context.GetEntitiesByExportPlatformIndex(true, PlatForm.All)
			let entityList = list.concat(allEntity, platEntity)
			this.onGenerateCode(entityList, PlatForm.All as PlatForm)
		// }
	}

	//生成代码
	onGenerateCode(entityList : Array<ConfigDataEntity>, platForm : PlatForm){
		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.startGeCode(e)
			}
		}

		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.beforeGenCode(e)
			}
		}

		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.genCode(e)
			}
		}


		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.afterGenCode(e)
			}
		}

		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			generator.genCodeEnd()
		}
	}

	//生成数据
	generateData(entityList : Array<ConfigDataEntity>, platform : PlatForm){
		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.startGeData(e)
			}
		}

		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.beforeGenData(e)
			}
		}

		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.genData(e)
			}
		}


		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			for (let j = 0; j < entityList.length; j++) {
				var e = entityList[j]
				if (e.hasExportEnd()){
					continue
				}
				generator.afterGenData(e)
			}
		}

		for (let i = 0; i < this.codeGenerators.length; i++) {
			var generator = this.codeGenerators[i]
			generator.genDataEnd()
		}
	}

	createExportEntity(entityList : Array<ConfigDataEntity>, plat : PlatForm){
		let e = entityList[0]
		let eEntity = context.createEntity()
		eEntity.addFileName(e.fileName.value)
		eEntity.addSheetName(e.sheetName.value)
		eEntity.addFullName(e.fullName.value)
		eEntity.addExport(true)
		eEntity.addPlatform(plat)
		eEntity.addOnGenerateHeadDataAction([])
		eEntity.addOnGenerateCodeAction([])
		eEntity.addIndexInitMethodNameDict(new Map<string,MethodInfo>())
		let list = e.memberHeadDataList.value
		let array = []
		eEntity.addMemberHeadDataList(array.concat(list))
		for (let i = 0; i < entityList.length; i++) {
			var entity = entityList[i]
			if (!entity.hasSplit() && entityList.length > 1){
				console.error(`[解析Split]  解析Split错误, 如果有任意一个文件被标记为Split, 那么所有的同名SheetName都应该为Split, 文件名:${entity.fullName.value}, Sheet_Name:${entity.reallySheetName.value}.`)
				process.exit(1)
			}
			EntityService.mergeEntityData(eEntity, entity)
		}
		ExcelService.createColumnEntityList(eEntity)
	}

	async readFile(filePath : string, ) : Promise<void>{
		if( filePath.startsWith("~$")){
			return
		}
		return new Promise(resolve => {
			var book = new Workbook()
			book.xlsx.readFile(filePath).then(()=>{
				book.eachSheet((sheet, id)=>{
					if (sheet.name.startsWith('!') || sheet.name.startsWith('！'))
					{
						return
					}
					let entity = this.createSheetEntity(filePath, sheet)
					this.excelDataList.push(entity)
					resolve()
				})
			})
		});
	}

	mergeExportEntity(){
		let idx = context._SheetNameIndex.index
		idx.forEach((v : Map<any,ConfigDataEntity>,k)=>{
			let has_plat = this.checkEntitiesPlat(v)
			if(has_plat){
				let mergeDict = this.mergePlatEntity(v)
				mergeDict.forEach((v, k)=>{
					this.createExportEntity(v, k as PlatForm)
				})
			}else{
				let e_list = new Array<ConfigDataEntity>()
				v.forEach((v, k)=>{
					if (!v.hasExport()){
						e_list.push(v)
					}
				})
				this.createExportEntity(e_list, PlatForm.All)
			}
		})
	}

	checkEntitiesPlat(entityList :  Map<string,ConfigDataEntity>) : boolean{
		let bFind = false
		entityList.forEach((v,k)=>{
			if (v.hasPlatform()){
				bFind = true
			}else if (bFind){
				console.error(`[平台检测] 配置表工具检测到表格平台配置错误,  错误文件名:${v.fullName.value} 错误Sheet名${v.sheetName.value},`)
			}
		})
		return bFind
	}

	mergePlatEntity(entityList : Map<string,ConfigDataEntity>) : Map<string, Array<ConfigDataEntity>>{
		let plat_dict : Map<string, Array<ConfigDataEntity>> = new Map<string, Array<ConfigDataEntity>>()
		entityList.forEach((v, k)=> {
			if (v.hasExport()){
				return
			}
			let list = plat_dict.getOrDefault(v.platform.value, [])
			list.push(v)
		})
		return plat_dict
	}

	createSheetEntity(filePath : string, sheet : Worksheet){
		try {
			let entity = context.createEntity("")
			entity.addFullName(filePath)
			entity.addSheetName(sheet.name)
			entity.addFileName(path.basename(filePath))
			this.parseSheetName(sheet.name, entity)
			this.parseFileName(sheet.name, entity)
			entity.addSheetData(sheet)
			entity.replaceMemberHeadDataList(ExcelService.parseHeadData(entity))
			return entity
		}catch (e) {
			console.log(`[创建Entity] 创建Entity失败, 文件路径: ${filePath}, SheetName:${sheet.name}`)
		}
	}

	parseSheetName(sheetName : string, entity : ConfigDataEntity){
		try {
			let re_ret = sheetName.match(/"(.*)_[Ss]plit[0-9]+"/)
			if (re_ret != null){
				let really_sheet_name = re_ret.groups[1]
				entity.addSheetName(really_sheet_name)
				entity.setSplit(true)
			}else{
				entity.addReallySheetName(sheetName)
			}
		}catch (e){
			console.error(`[解析SheetName] 配置表解析SheetName失败. 文件名: ${entity.fullName.value}, SheetName:${sheetName} ${e}`)
		}
	}

	parseFileName(file_name : string, entity : ConfigDataEntity){
		file_name = file_name.replace(".xlsx", "")
		let sp_ret = file_name.split('@')
		if (sp_ret.length == 1)
		{
			entity.addPlatform(PlatForm.All)
			return
		}
		let sp_ret2 = sp_ret[1].split("|")
		if (sp_ret2.length == 1)
		{
			return
		}
		sp_ret2.forEach((sp,k)=>{
			let sp_ret3 = sp.split("=")
			if (sp_ret3.length != 2){
				console.error(`[解析文件名错误] 参数格式应该为 xx=xx, c: ${file_name}`)
				process.exit(1)
			}
			if (sp_ret3[0] == "p"){
				if (PlatForm[sp_ret3[1]] == null) {
					console.error(`[平台] 平台配置错误,应该为p=Android || IOS || Amazon, 错误文件名: ${file_name}`)
					process.exit(1)
				}
				entity.addPlatform(sp_ret3[1])
			}
		})
	}
}